#-------------------------------------------------------------------------------
# Name:        Computer
# Purpose:
#
# Author:      Michael Blackwood
#
# Created:     07/11/2013
# Copyright:   (c) Monxcleyr Productions 2013
# Licence:     GPL v3
#-------------------------------------------------------------------------------
#!/usr/bin/env python

import pygame, os, logging, random
import config

class Computer():

  """ The ships main computer. """

  def __init__(self, dialog):
    self.conf = config.Config()
    self.minigamecomplete = False
    self.status = {}
    self.loadComputer()
    # Holds if we just failed a task (not counting timeout)
    self.failedtask = False

    self.tasks = {}
    self.dialog = dialog

    # Load maintenance script
    self.loadScript('maintenance.ini', self.tasks)
    self.emergencycount = 0

#-------------------------------------------------------------------------------

  def update(self, time, common, objecthandler):

    """ Updates the computer each frame. """

    # Check if a minigame was just completed
    self.checkMiniGame(self.tasks, common, objecthandler)

    # Checj if any tasks timedout before being interacted with
    self.checkTimeout(self.tasks, time, common, objecthandler)

    # Check if any unactivated tasks need to activate at this time
    self.checkActivate(self.tasks, time, common, objecthandler)

    # Check if any emergencies are running
    self.emergency['running'] = False
    for task in self.getActiveTask(self.tasks):
      if self.tasks[task]['emergency']:
        self.emergency['running'] = True

    if common.keyState.check(common.key.bind['use'])[0] == True:
      self.generateEmergency(self.tasks, common, objecthandler, time, (1,3), (1,5), 20)

#-------------------------------------------------------------------------------

  def generateEmergency(self, taskdict, common, objecthandler, time, systemrange, penaltyrange, duration):

    if (time + 1) in taskdict:
      common.debug.add('Cannot add emergency at ' + str(time + 1))
      return None

    self.emergencycount += 1


    emergency = {}

    # gather consoles that can take an emergency event:
    consoles = []
    for console in objecthandler.getObjectAncestorList('console'):
      if console.attributes['emergency']:
        consoles.append(console)

    # Choose console to activate
    system = random.choice(list(self.status.keys()))
    consolenames = []
    for console in consoles:
      if console.attributes['system'] == system:
        consolenames.append(console.name)

    # Choose systems to affect
    count = random.randint(systemrange[0], systemrange[1])
    systems = []
    # include the system the console is made for
    systems.append(system)

    # add random systems to be affected
    status = list(self.status.keys())
    while len(systems) < count:
      system = random.choice(status)
      if system not in systems:
        systems.append(system)

    # generate panalties
    penalties = []
    while len(penalties) < count:
      penalties.append(random.randint(penaltyrange[0], penaltyrange[1]))


    emergency['name'] = 'generated_emergency_' + str(self.emergencycount)
    emergency['time'] = time + 1
    emergency['system'] = system
    emergency['console'] = random.choice(consolenames)
    emergency['systems'] = systems
    emergency['penalties'] = penalties
    emergency['visable'] = objecthandler.getObject(emergency['console']).attributes['visable']
    emergency['duration'] = duration
    emergency['emergency'] = True
    emergency['active'] = False
    emergency['complete'] = False

    # generate dialog stuff, yo
    emergency['dialogtheme'] = self.emergency['dialogtheme']
    emergency['dialogpos'] = self.emergency['dialogpos']
    index = random.randrange(0, len(self.emergency['dialogtexts']))
    emergency['dialogtext'] = random.choice(self.emergencytexts)

    logging.debug('Generated emergency')

    taskdict[time+1] = emergency


  def checkMiniGame(self, taskdict, common,  objecthandler):

    """ Checks if a minigame was completed, and if so, update stuff accordingly. """

    if self.minigamecomplete == True:
      self.minigamecomplete = False

      result = None
      console = None
      obj = None
      for obj in objecthandler.getObjectAncestorList('console'):
        if obj.attributes['result'] != None:
          result = obj.attributes['result']
          console = obj.name
          obj = obj
          obj.reset()


      for task in taskdict:
        if taskdict[task]['active']:
          if taskdict[task]['console'] == console:
            taskdict[task]['active'] = False
            taskdict[task]['complete'] = True
            taskdict[task]['emergency'] = False
            obj.attributes['visable'] = taskdict[task]['visable']
            if result:
              self.calculatePenalties(taskdict[task], True)
              logging.debug('Completed task "%s"', taskdict[task]['name'])
              common.debug.add('Completed task "' + taskdict[task]['name'] + '"')
            else:
              self.calculatePenalties(taskdict[task], False)
              logging.debug('Failed task "%s"', taskdict[task]['name'])
              common.debug.add('Failed task "' + taskdict[task]['name'] + '"')

    common.debug.setRight(str(self.status))


  def checkTimeout(self, taskdict, time, common, objecthandler):

    """ Checks currently active tasks, if they're duration ends, mark them as inactive. """

    for task in taskdict:
      if taskdict[task]['active']:
        if time >= taskdict[task]['time'] + taskdict[task]['duration']:
          taskdict[task]['active'] = False
          logging.debug('Failed to complete task "%s"', taskdict[task]['name'])
          common.debug.add('Failed to complete task "' + taskdict[task]['name'] + '"')
          self.calculatePenalties(taskdict[task], False)

          for obj in objecthandler.getObjectAncestorList('console'):
            if obj.name == taskdict[task]['console']:
              obj.attributes['visable'] = taskdict[task]['visable']
              obj.reset()


  def checkActivate(self, taskdict, time, common, objecthandler):

    """ Checks if any tasks need to activate and then sets them active. """

    consolename = ''
    if taskdict.get(time):
      # Acivate the task
      if not taskdict[time]['active'] and not taskdict[time]['complete']:
        logging.debug('Activating task "%s"', taskdict[time]['name'])
        common.debug.add('Activating task "' + taskdict[time]['name'] + '"')
        taskdict[time]['active'] = True
        if taskdict[time]['emergency'] == True:
          self.emergency['running'] = True
        # Activate the console
        for obj in objecthandler.getObjectAncestorList('console'):
          if obj.name == taskdict[time]['console']:
            obj.attributes['visable'] = True
            obj.attributes['required'] = True
            consolename = obj.attributes['name']

        # Activate a dialog, yo
        if taskdict[time]['dialogtheme']:
          name = taskdict[time]['name'] + '_dialog'
          self.dialog.addDialog(taskdict[time]['dialogtheme'], ' ', taskdict[time]['dialogpos'], [1], name)
          self.dialog.getDialogByName(name).loadText(taskdict[time]['dialogtext'])
          self.dialog.getDialogByName(name).attributes['consolename'] = consolename


  def getActiveTask(self, taskdict):

    """ Returns currently active tasks from the given dictionary of tasks """
    temp = []

    for task in taskdict:
      if taskdict[task]['active'] == True:
        temp.append(task)

    return temp

  def completeTask(self, taskdict, taskkey):

    """ Marks the given task as inactive and complete. """

    taskdict[taskkey]['complete'] = True
    taskdict[taskkey]['active'] = False


  def calculatePenalties(self, task, result):

    """ Applies penalties to systems. """

    for system in task['systems']:
      if result:
        self.status[system] -= task['penalties'][task['systems'].index(system)]
        if self.status[system] < 0:
          self.status[system] = 0
      else:
        self.status[system] += task['penalties'][task['systems'].index(system)]
        self.failedtask = True

#-------------------------------------------------------------------------------

  def loadEmergencyTexts(self, txtfile):

    self.emergencytexts = []
    with open('resources/dialogs/' + txtfile) as txt:

      for line in txt.readlines():
        self.emergencytexts.append(line.rstrip())


#-------------------------------------------------------------------------------

  def loadComputer(self):

    self.status = {}

    self.conf.read('resources/configs/computer.ini')
    self.status = dict(self.conf.items('Systems'))

    for key in self.status:
      self.status[key] = int(self.status[key])


    self.emergency = {}
    self.emergency['running'] = False
    self.emergency['start'] = self.convertTime(self.conf.get('Emergencies', 'start'))

    pos = self.conf.get('Emergencies', 'dialogpos')
    pos = pos.replace(' ', '')
    pos = pos.split(',')

    temp = []
    for i in pos:
      temp.append(int(i))

    self.emergency['dialogpos'] = temp
    self.emergency['dialogtexts'] = self.conf.get('Emergencies', 'dialogtexts')
    self.emergency['dialogtheme'] = self.conf.get('Emergencies', 'dialogtheme')

    self.loadEmergencyTexts(self.emergency['dialogtexts'])

    logging.info('Initialized Computer')

#-------------------------------------------------------------------------------

  def loadScript(self, filename, scriptdict):

    """ Load a script and place it into var """

    self.conf = config.Config()
    self.conf.read(os.path.join('resources/scripts', filename))

    sections = self.conf.sections()

    tasks = []

    # throw the contents of each task into a dict to be processed later
    for task in sections:
      contents = dict(self.conf.items(task))
      contents['name'] = task
      tasks.append(contents)

    for task in tasks:

      task['emergency'] = task['emergency'] == 'True'
      task['time'] = self.convertTime(task['time'])
      task['duration'] = self.convertTime(task['duration'])
      task['active'] = False
      task['complete'] = False
      task['visable'] = task['visable'] == 'True'
      systems = task['systems']
      systems = systems.replace(' ', '')
      systems = systems.split(',')

      task['systems'] = systems

      penalties = task['penalties']
      penalties = penalties.replace(' ', '')
      penalties = penalties.split(',')

      temp = []
      for penalty in penalties:
        temp.append(int(penalty))

      task['penalties'] = temp

      if 'dialogtheme' in task:
        pos = task['dialogpos']
        pos = pos.replace(' ', '')
        pos = pos.split(',')

        temp = []
        for i in pos:
          temp.append(int(i))

        task['dialogpos'] = temp
      else:
        task['dialogtheme'] = None

      scriptdict[task['time']] = task

    logging.info('Loaded Computer script "%s"', filename[:-4])



  def convertTime(self, time):

    """ Convert a string time in 00:00 format to integer seconds """

    split = time.split(':')

    converted = 0
    #check that there was actually a minute supplied
    if split[0]:
      converted = int(split[0]) * 60

    converted += int(split[1])

    return converted


